import { Router } from 'express';
import { body } from 'express-validator';
import utils from '../helpers/utils.js';
import validateFormData from '../helpers/validate_form.js';
import DB from '../models/db.js';
import config from '../config.js';
import EthersUtils from '../helpers/ethers_utils.js';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const router = Router();

// 获取当前模块的目录路径
const __dirname = path.dirname(fileURLToPath(import.meta.url));

/**
 * Route to list smartcontracts records
 * @GET /smartcontracts/index/{fieldname}/{fieldvalue}
 */
router.get(['/', '/index/:fieldname?/:fieldvalue?'], async (req, res) => {  
	try{
		const query = {};
		let queryFilters = [];
		let where = {};
		let replacements = {};
		let fieldName = req.params.fieldname;
		let fieldValue = req.params.fieldvalue;
		
		if (fieldName){
			queryFilters.push(DB.filterBy(fieldName, fieldValue));
		}
		let search = req.query.search;
		if(search){
			let searchFields = DB.SmartContracts.searchFields();
			where[DB.op.or] = searchFields;
			replacements.search = `%${search}%`;
		}
		
		if(queryFilters.length){
			where[DB.op.and] = queryFilters;
		}
		query.raw = true;
		query.where = where;
		query.replacements = replacements;
		query.order = DB.getOrderBy(req, 'id', 'desc');
		query.attributes = DB.SmartContracts.listFields();
		let page = parseInt(req.query.page) || 1;
		let limit = parseInt(req.query.limit) || 10;
		let result = await DB.SmartContracts.paginate(query, page, limit);
		return res.ok(result);
	}
	catch(err) {
		return res.serverError(err);
	}
});

/**
 * Route to view SmartContracts record
 * @GET /smartcontracts/view/{recid}
 */
router.get('/view/:recid', async (req, res) => {
	try{
		const recid = req.params.recid || null;
		const query = {}
		const where = {}
		where['id'] = recid;
		query.raw = true;
		query.where = where;
		query.attributes = DB.SmartContracts.viewFields();
		let record = await DB.SmartContracts.findOne(query);
		if(!record){
			return res.notFound();
		}
		return res.ok(record);
	}
	catch(err){
		return res.serverError(err);
	}
});

/**
 * Route to insert SmartContracts record
 * @POST /smartcontracts/add
 */
router.post('/add/', 
	[
		body('contract_name').not().isEmpty(),
		body('contract_address').not().isEmpty(),
		body('version').not().isEmpty(),
		body('category').not().isEmpty(),
		body('description').optional({nullable: true, checkFalsy: true}),
		body('creator_address').optional({nullable: true, checkFalsy: true}),
		body('path').optional({nullable: true, checkFalsy: true}),
	], validateFormData
, async function (req, res) {
	try{
		let modeldata = req.getValidFormData();
		
		//save SmartContracts record
		let record = await DB.SmartContracts.create(modeldata);
		//await record.reload(); //reload the record from database
		const recid =  record['id'];
		
		return res.ok(record);
	} catch(err){
		return res.serverError(err);
	}
});

/**
 * Route to get  SmartContracts record for edit
 * @GET /smartcontracts/edit/{recid}
 */
router.get('/edit/:recid', async (req, res) => {
	try{
		const recid = req.params.recid;
		const query = {};
		const where = {};
		where['id'] = recid;
		query.raw = true;
		query.where = where;
		query.attributes = DB.SmartContracts.editFields();
		let record = await DB.SmartContracts.findOne(query);
		if(!record){
			return res.notFound();
		}
		return res.ok(record);
	}
	catch(err){
		return res.serverError(err);
	}
});

/**
 * Route to update  SmartContracts record
 * @POST /smartcontracts/edit/{recid}
 */
router.post('/edit/:recid', 
	[
		body('contract_name').optional({nullable: true}).not().isEmpty(),
		body('contract_address').optional({nullable: true}).not().isEmpty(),
		body('version').optional({nullable: true}).not().isEmpty(),
		body('category').optional({nullable: true}).not().isEmpty(),
		body('description').optional({nullable: true, checkFalsy: true}),
		body('creator_address').optional({nullable: true, checkFalsy: true}),
		body('path').optional({nullable: true, checkFalsy: true}),
	], validateFormData
, async (req, res) => {
	try{
		const recid = req.params.recid;
		let modeldata = req.getValidFormData({ includeOptionals: true });
		const query = {};
		const where = {};
		where['id'] = recid;
		query.raw = true;
		query.where = where;
		query.attributes = DB.SmartContracts.editFields();
		let record = await DB.SmartContracts.findOne(query);
		if(!record){
			return res.notFound();
		}
		await DB.SmartContracts.update(modeldata, {where: where});
		return res.ok(modeldata);
	}
	catch(err){
		return res.serverError(err);
	}
});

/**
 * Route to delete SmartContracts record by table primary key
 * Multi delete supported by recid separated by comma(,)
 * @GET /smartcontracts/delete/{recid}
 */
router.get('/delete/:recid', async (req, res) => {
	try{
		const recid = (req.params.recid || '').split(',');
		const query = {};
		const where = {};
		where['id'] = recid;
		query.raw = true;
		query.where = where;
		let records = await DB.SmartContracts.findAll(query);
		records.forEach(async (record) => { 
			//perform action on each record before delete
		});
		await DB.SmartContracts.destroy(query);
		return res.ok(recid);
	}
	catch(err){
		return res.serverError(err);
	}
});

// 管理员私钥配置（实际项目中应该从安全配置中获取）
const ADMIN_PRIVATE_KEY = config.eth.privateKey;

// 在路由处理函数中添加文件保存逻辑（在部署合约成功后）
const saveContractToFile = (contractInfo) => {
    try {
        // 获取前端合约文件路径
        const frontendContractPath = path.resolve(
            process.cwd(),
            '../frontend/src/services/contract.json'
        );
        
        // 确保目录存在
        const frontendContractDir = path.dirname(frontendContractPath);
        if (!fs.existsSync(frontendContractDir)) {
            fs.mkdirSync(frontendContractDir, { recursive: true });
            console.log(`创建前端合约存储目录: ${frontendContractDir}`);
        }

        // 读取现有的合约信息（如果存在）
        let existingContracts = {};
        if (fs.existsSync(frontendContractPath)) {
            existingContracts = JSON.parse(fs.readFileSync(frontendContractPath, 'utf8'));
        }

        // 更新合约信息
        const contractName = Object.keys(contractInfo)[0];
        existingContracts[contractName] = {
            address: contractInfo[contractName].address,
            abi: contractInfo[contractName].abi,
            bytecode: contractInfo[contractName].bytecode,
            logicAddress: contractInfo[contractName].logicAddress,
            storageAddress: contractInfo[contractName].storageAddress,
            category: contractInfo[contractName].category,
            version: contractInfo[contractName].version,
            description: contractInfo[contractName].description,
            creator: contractInfo[contractName].creator,
            date: new Date().toISOString()
        };

        // 写入文件
        fs.writeFileSync(
            frontendContractPath,
            JSON.stringify(existingContracts, null, 2)
        );
        console.log(`合约信息已成功保存到前端: ${frontendContractPath}`);

        // 验证文件是否成功写入
        if (fs.existsSync(frontendContractPath)) {
            console.log(`前端文件验证成功: ${frontendContractPath}`);
            return true;
        } else {
            console.error(`前端文件保存失败: ${frontendContractPath}`);
            return false;
        }
    } catch (error) {
        console.error('保存合约信息到前端文件失败:', error);
        console.error('错误详情:', error.stack);
        return false;
    }
};

//  部署智能合约
//  @POST /smartcontracts/deploy
router.post('/deploy/', 
    [
        body('contract_name').not().isEmpty(),
        body('contract_file_path').not().isEmpty(),
        body('version').not().isEmpty(),
        body('category').not().isEmpty(),
        body('description').optional({nullable: true, checkFalsy: true}),
        body('constructor_args').optional({nullable: true, checkFalsy: true}),
        body('storage_address').optional({nullable: true, checkFalsy: true}),
    ], 
    validateFormData,
    async (req, res) => {
        try {
            // 1. 获取表单数据
            const formData = req.getValidFormData();
            const constructorArgs = formData.constructor_args 
                ? JSON.parse(formData.constructor_args) 
                : [];
            
            // 2. 构建完整的文件路径
            const tempFilePath = path.resolve(
                process.cwd(),
				"assets/",
                formData.contract_file_path
            );
            
            console.log('临时文件路径:', tempFilePath);
            
            // 3. 验证文件存在
            if (!fs.existsSync(tempFilePath)) {
                console.error('合约文件不存在:', tempFilePath);
                return res.badRequest('Contract file not found');
            }

            // 4. 创建合约目录
            const contractsDir = path.resolve(process.cwd(), 'assets/uploads/contracts');
            if (!fs.existsSync(contractsDir)) {
                fs.mkdirSync(contractsDir, { recursive: true });
                console.log('创建合约目录:', contractsDir);
            }

            // 5. 将文件从temp移动到contracts目录
            const fileName = path.basename(tempFilePath);
            const targetPath = path.join(contractsDir, fileName);
            
            // 如果目标文件已存在，先删除
            if (fs.existsSync(targetPath)) {
                fs.unlinkSync(targetPath);
            }
            
            // 移动文件
            fs.renameSync(tempFilePath, targetPath);
            console.log('文件已移动到:', targetPath);
            
            // 6. 读取合约文件内容
            const sourceCode = fs.readFileSync(targetPath, 'utf8');
            
            // 7. 更新文件路径为新的位置
            formData.contract_file_path = path.relative(process.cwd(), targetPath);
            
            // 8. 初始化以太坊工具
            const ethersUtils = new EthersUtils(ADMIN_PRIVATE_KEY, {
                network: 'holesky'
            });

            // 9. 编译合约
            const compileResult = await ethersUtils.compileContract(
                sourceCode,
                formData.contract_name,
                './build/contracts'
            );

            let deploymentResult;
            let deploymentOptions = {
                contractName: formData.contract_name,
                outputDir: './build/contracts'
            };

            // 10. 根据合约类型选择部署方式
            if (formData.category === 'data') {
                // 部署存储合约（普通部署）
                deploymentResult = await ethersUtils.deployContract(
                    compileResult,
                    constructorArgs,
                    deploymentOptions
                );
            } else if (formData.category === 'operation') {
                // 验证是否提供了存储合约地址
                if (!formData.storage_address) {
                    return res.badRequest('部署逻辑合约需要提供存储合约地址');
                }

                // 添加存储合约地址到部署选项
                deploymentOptions.storageAddress = formData.storage_address;
                deploymentOptions.isUpgradeable = true;

                // 部署逻辑合约（可升级部署）
                deploymentResult = await ethersUtils.deployContract(
                    compileResult,
                    constructorArgs,
                    deploymentOptions
                );
            } else {
                return res.badRequest('Invalid contract category');
            }

            // 11. 构造合约信息对象
            const contractInfo = {
                [formData.contract_name]: {
                    address: deploymentResult.address,
                    abi: deploymentResult.abi,
                    bytecode: deploymentResult.bytecode,
                    version: formData.version,
                    isUpgradeable: formData.category === 'operation',
                    storageAddress: formData.storage_address
                }
            };

            // 12. 保存合约信息到文件
            const success = saveContractToFile(contractInfo);

            // 13. 将合约信息存入数据库
            const modeldata = {
                contract_name: formData.contract_name,
                contract_address: deploymentResult.address,
                version: formData.version,
                category: formData.category,
                description: formData.description,
                creator_address: ethersUtils.address,
                path: formData.contract_file_path,
                storage_address: formData.storage_address
            };

            const record = await DB.SmartContracts.create(modeldata);

            // 14. 返回结果
            return res.ok({
                message: '合约部署成功',
                contract: {
                    id: record.id,
                    name: record.contract_name,
                    address: record.contract_address,
                    version: record.version,
                    creator: record.creator_address,
                    path: record.path,
                    isUpgradeable: formData.category === 'operation',
                    storageAddress: record.storage_address
                },
                compile: compileResult,
            });
        } catch (err) {
            console.error('合约部署失败:', err);
            return res.serverError(err.message);
        }
    }
);

// 教务人员地址文件路径
const REGISTRAR_FILE_PATH = path.resolve(
    process.cwd(),
    'assets/data/registrars.json'
);

// 保存教务人员地址到文件
const saveRegistrarToFile = (address, personalId, name) => {
    try {
        // 确保目录存在
        const dir = path.dirname(REGISTRAR_FILE_PATH);
        if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true });
        }

        // 读取现有数据
        let registrars = {};
        if (fs.existsSync(REGISTRAR_FILE_PATH)) {
            registrars = JSON.parse(fs.readFileSync(REGISTRAR_FILE_PATH, 'utf8'));
        }

        // 添加或更新教务人员信息
        registrars[address.toLowerCase()] = {
            personalId,
            name,
            addedAt: new Date().toISOString()
        };

        // 写入文件
        fs.writeFileSync(REGISTRAR_FILE_PATH, JSON.stringify(registrars, null, 2));
        return true;
    } catch (error) {
        console.error('保存教务人员信息失败:', error);
        return false;
    }
};

// 从文件中删除教务人员地址
const removeRegistrarFromFile = (address) => {
    try {
        if (!fs.existsSync(REGISTRAR_FILE_PATH)) {
            return true;
        }

        // 读取现有数据
        let registrars = JSON.parse(fs.readFileSync(REGISTRAR_FILE_PATH, 'utf8'));
        
        // 删除指定地址
        delete registrars[address.toLowerCase()];

        // 写入文件
        fs.writeFileSync(REGISTRAR_FILE_PATH, JSON.stringify(registrars, null, 2));
        return true;
    } catch (error) {
        console.error('删除教务人员信息失败:', error);
        return false;
    }
};

/**
 * Route to get registrar information
 * @GET /smartcontracts/registrars
 */
router.get('/registrars', async (req, res) => {
    try {
        // 1. 检查文件是否存在
        if (!fs.existsSync(REGISTRAR_FILE_PATH)) {
            return res.ok([]);
        }

        // 2. 读取并验证JSON数据
        let registrars = {};
        try {
            const fileContent = fs.readFileSync(REGISTRAR_FILE_PATH, 'utf8');
            registrars = JSON.parse(fileContent);
            
            // 验证数据结构
            if (typeof registrars !== 'object' || registrars === null) {
                throw new Error('Invalid registrars data format');
            }
        } catch (err) {
            console.error('Failed to parse registrars file:', err);
            return res.serverError('Failed to load registrar data');
        }

        const addresses = Object.keys(registrars);

        console.log('Addresses from file:', addresses);

        // 3. 从数据库获取用户信息 - 使用新的忽略大小写查询方法
        const users = await DB.Users.findAll({
            where: {
                [DB.op.or]: addresses.map(addr => 
                    DB.filterByCaseInsensitive('ethereum_address', addr)
                )
            },
            attributes: ['ethereum_address', 'personnel_id', 'name']
        });

        console.log('Users from database:', users);

        // 4. 合并并验证结果
        const result = users.map(user => {
            const registrarInfo = registrars[user.ethereum_address.toLowerCase()];
            if (!registrarInfo) {
                return null;
            }
            return {
                address: user.ethereum_address,
                personalId: user.personnel_id,
                name: user.name,
                addedAt: registrarInfo.addedAt
            };
        }).filter(Boolean); // 过滤掉无效记录

        return res.ok(result);
    } catch (err) {
        console.error('Error getting registrars:', err);
        return res.serverError(err.message);
    }
});

/**
 * Route to add educational staff addresses in batch
 * @POST /smartcontracts/add-registrar
 */
router.post('/add-registrar', 
    [
        body('addresses').isArray().not().isEmpty(),
        body('addresses.*').isEthereumAddress(),
    ], 
    validateFormData,
    async (req, res) => {
        try {
            const { addresses } = req.getValidFormData();
            
            // 从数据库获取最新的逻辑合约地址
            const latestContract = await DB.SmartContracts.findOne({
                where: {
                    category: 'operation'
                },
                order: [['date_created', 'DESC']]
            });

            if (!latestContract) {
                return res.badRequest('No logic contract found in database');
            }

            // 读取逻辑合约ABI
            const logicContractPath = path.resolve(
                __dirname,
                '../helpers/build/contracts/GradeLogicV1.json'
            );
            
            if (!fs.existsSync(logicContractPath)) {
                return res.badRequest('Logic contract ABI not found');
            }

            const logicContractData = JSON.parse(fs.readFileSync(logicContractPath, 'utf8'));
            
            // 初始化以太坊工具
            const ethersUtils = new EthersUtils(ADMIN_PRIVATE_KEY, {
                network: 'holesky'
            });

            // 创建合约实例
            const contract = ethersUtils.getContract(
                latestContract.contract_address,
                logicContractData.abi
            );

            // 获取用户信息
            const users = await DB.Users.findAll({
                where: {
                    ethereum_address: addresses
                },
                attributes: ['ethereum_address', 'personnel_id', 'name']
            });

            // 批量添加教务人员地址
            const transactions = [];
            for (const address of addresses) {
                const tx = await contract.addRegistrar(address);
                transactions.push(tx);

                // 保存到文件
                const user = users.find(u => u.ethereum_address.toLowerCase() === address.toLowerCase());
                if (user) {
                    saveRegistrarToFile(address, user.personnel_id, user.name);
                }
            }

            // 等待所有交易确认
            const receipts = await Promise.all(transactions.map(tx => tx.wait()));

            return res.ok({
                message: 'Successfully added registrar addresses',
                transactionHashes: receipts.map(r => r.hash),
                addresses: addresses
            });
        } catch (err) {
            console.error('Error adding registrar:', err);
            return res.serverError(err.message);
        }
    }
);

/**
 * Route to remove registrar address
 * @POST /smartcontracts/remove-registrar
 */
router.post('/remove-registrar', 
    [
        body('address').isEthereumAddress(),
    ], 
    validateFormData,
    async (req, res) => {
        try {
            const { address } = req.getValidFormData();
            
            // 从数据库获取最新的逻辑合约地址
            const latestContract = await DB.SmartContracts.findOne({
                where: {
                    category: 'operation'
                },
                order: [['date_created', 'DESC']]
            });

            if (!latestContract) {
                return res.badRequest('No logic contract found in database');
            }

            // 读取逻辑合约ABI
            const logicContractPath = path.resolve(
                __dirname,
                '../helpers/build/contracts/GradeLogicV1.json'
            );
            
            if (!fs.existsSync(logicContractPath)) {
                return res.badRequest('Logic contract ABI not found');
            }

            const logicContractData = JSON.parse(fs.readFileSync(logicContractPath, 'utf8'));
            
            // 初始化以太坊工具
            const ethersUtils = new EthersUtils(ADMIN_PRIVATE_KEY, {
                network: 'holesky'
            });

            // 创建合约实例
            const contract = ethersUtils.getContract(
                latestContract.contract_address,
                logicContractData.abi
            );

            // 调用合约移除教务人员
            const tx = await contract.removeRegistrar(address);
            const receipt = await tx.wait();

            // 从文件中移除教务人员信息
            removeRegistrarFromFile(address);

            return res.ok({
                message: 'Successfully removed registrar address',
                transactionHash: receipt.hash,
                address: address
            });
        } catch (err) {
            console.error('Error removing registrar:', err);
            return res.serverError(err.message);
        }
    }
);

export default router;
